"""错误诊断分析节点"""

import re
from typing import Dict, List, Any, Optional, Tuple
from core.graph.chat_graph import ChatState, ErrorDiagnosisResult


class CairoErrorAnalyzer:
    """Cairo 错误分析器"""
    
    def __init__(self):
        self.error_patterns = {
            "type_mismatch": {
                "patterns": [
                    r"type mismatch",
                    r"expected.*found",
                    r"mismatched types",
                    r"类型不匹配",
                    r"类型错误"
                ],
                "category": "type_error",
                "severity": "error"
            },
            "ownership_error": {
                "patterns": [
                    r"borrow.*after move",
                    r"use of moved value",
                    r"cannot borrow.*as mutable",
                    r"所有权错误",
                    r"借用检查失败"
                ],
                "category": "ownership",
                "severity": "error"
            },
            "undefined_variable": {
                "patterns": [
                    r"cannot find.*in this scope",
                    r"undefined variable",
                    r"unresolved name",
                    r"未定义的变量",
                    r"找不到变量"
                ],
                "category": "scope",
                "severity": "error"
            },
            "syntax_error": {
                "patterns": [
                    r"syntax error",
                    r"unexpected token",
                    r"expected.*found",
                    r"语法错误",
                    r"语法不正确"
                ],
                "category": "syntax",
                "severity": "error"
            },
            "compilation_error": {
                "patterns": [
                    r"compilation failed",
                    r"failed to compile",
                    r"编译失败",
                    r"编译错误"
                ],
                "category": "compilation",
                "severity": "error"
            },
            "runtime_panic": {
                "patterns": [
                    r"panic",
                    r"assertion failed",
                    r"index out of bounds",
                    r"运行时错误",
                    r"断言失败"
                ],
                "category": "runtime",
                "severity": "error"
            },
            "contract_error": {
                "patterns": [
                    r"contract.*not found",
                    r"invalid contract",
                    r"contract call failed",
                    r"合约错误",
                    r"合约调用失败"
                ],
                "category": "contract",
                "severity": "error"
            }
        }
        
        self.fix_suggestions = {
            "type_mismatch": [
                {
                    "description": "检查变量类型是否匹配",
                    "code_example": "let x: felt252 = 42_felt252;  // 明确指定类型",
                    "priority": "high"
                },
                {
                    "description": "使用类型转换函数",
                    "code_example": "let x: u32 = value.try_into().unwrap();",
                    "priority": "medium"
                }
            ],
            "ownership_error": [
                {
                    "description": "使用引用而不是移动所有权",
                    "code_example": "fn process_data(data: @Array<felt252>) { ... }",
                    "priority": "high"
                },
                {
                    "description": "克隆数据以避免所有权问题",
                    "code_example": "let data_copy = data.clone();",
                    "priority": "medium"
                }
            ],
            "undefined_variable": [
                {
                    "description": "检查变量是否已声明",
                    "code_example": "let variable_name = initial_value;",
                    "priority": "high"
                },
                {
                    "description": "检查导入语句",
                    "code_example": "use module_name::function_name;",
                    "priority": "medium"
                }
            ],
            "syntax_error": [
                {
                    "description": "检查括号、分号和大括号是否匹配",
                    "code_example": "fn example() { ... }  // 确保括号匹配",
                    "priority": "high"
                },
                {
                    "description": "检查关键字拼写",
                    "code_example": "fn function_name() -> ReturnType { ... }",
                    "priority": "medium"
                }
            ],
            "runtime_panic": [
                {
                    "description": "使用安全的数组访问",
                    "code_example": "if index < array.len() { array[index] }",
                    "priority": "high"
                },
                {
                    "description": "使用 Result 类型处理可能失败的操作",
                    "code_example": "match operation() { Ok(value) => ..., Err(e) => ... }",
                    "priority": "medium"
                }
            ],
            "contract_error": [
                {
                    "description": "检查合约地址是否正确",
                    "code_example": "let contract = IContractDispatcher { contract_address };",
                    "priority": "high"
                },
                {
                    "description": "添加错误处理",
                    "code_example": "match contract.call() { Ok(result) => ..., Err(e) => ... }",
                    "priority": "medium"
                }
            ]
        }

    def extract_error_info(self, text: str) -> Dict[str, Any]:
        """提取错误信息"""
        error_info = {
            "has_error": False,
            "error_messages": [],
            "error_locations": [],
            "stack_trace": None
        }
        
        lines = text.split('\n')
        
        for i, line in enumerate(lines):
            line = line.strip()
            
            # 检测错误消息
            if any(keyword in line.lower() for keyword in ['error', '错误', 'panic', 'failed']):
                error_info["has_error"] = True
                error_info["error_messages"].append({
                    "line_number": i + 1,
                    "message": line,
                    "type": "error"
                })
            
            # 检测位置信息
            location_match = re.search(r'at\s+([^:]+):(\d+):(\d+)', line)
            if location_match:
                error_info["error_locations"].append({
                    "file": location_match.group(1),
                    "line": int(location_match.group(2)),
                    "column": int(location_match.group(3))
                })
            
            # 检测堆栈跟踪
            if 'stack trace' in line.lower() or 'traceback' in line.lower():
                # 收集后续几行作为堆栈跟踪
                stack_lines = []
                for j in range(i, min(i + 10, len(lines))):
                    if lines[j].strip():
                        stack_lines.append(lines[j])
                    else:
                        break
                error_info["stack_trace"] = '\n'.join(stack_lines)
        
        return error_info

    def classify_error_type(self, text: str) -> Tuple[str, float]:
        """分类错误类型"""
        text_lower = text.lower()
        best_match = "unknown"
        best_score = 0.0
        
        for error_type, config in self.error_patterns.items():
            score = 0.0
            pattern_count = len(config["patterns"])
            
            for pattern in config["patterns"]:
                if re.search(pattern, text_lower, re.IGNORECASE):
                    score += 1.0 / pattern_count
            
            if score > best_score:
                best_score = score
                best_match = error_type
        
        return best_match, best_score

    def analyze_root_cause(self, error_type: str, error_text: str, code_context: Dict[str, Any]) -> str:
        """分析错误根本原因"""
        root_causes = {
            "type_mismatch": "类型系统不匹配，通常是因为变量类型声明不正确或类型转换问题",
            "ownership_error": "所有权系统违规，变量在移动后被使用或借用规则冲突",
            "undefined_variable": "作用域问题，变量未在当前作用域中定义或导入",
            "syntax_error": "语法规则违反，代码不符合 Cairo 语言语法规范",
            "compilation_error": "编译过程失败，可能是依赖问题或代码结构错误",
            "runtime_panic": "运行时错误，通常是数组越界、断言失败或逻辑错误",
            "contract_error": "智能合约相关错误，可能是合约调用、状态管理或权限问题"
        }
        
        base_cause = root_causes.get(error_type, "未知错误类型")
        
        # 根据代码上下文细化原因
        if code_context.get("has_code"):
            code_type = code_context.get("code_type", "")
            if code_type == "contract" and error_type == "type_mismatch":
                base_cause += "，在合约开发中常见于存储变量类型定义或函数参数类型不匹配"
            elif code_type == "function" and error_type == "ownership_error":
                base_cause += "，在函数中常见于参数传递方式不正确（值传递 vs 引用传递）"
        
        return base_cause

    def generate_fix_suggestions(self, error_type: str, error_text: str, 
                               code_context: Dict[str, Any]) -> List[Dict[str, Any]]:
        """生成修复建议"""
        suggestions = self.fix_suggestions.get(error_type, [])
        
        # 根据具体错误内容和代码上下文定制建议
        customized_suggestions = []
        
        for suggestion in suggestions:
            customized = suggestion.copy()
            
            # 根据代码类型调整建议
            if code_context.get("code_type") == "contract":
                if error_type == "type_mismatch":
                    customized["description"] += "（在合约中特别注意存储变量的类型声明）"
                elif error_type == "ownership_error":
                    customized["description"] += "（合约函数参数建议使用引用类型）"
            
            # 根据错误文本调整建议
            if "felt252" in error_text and error_type == "type_mismatch":
                customized["code_example"] = "let value: felt252 = 42;  // 确保 felt252 类型正确"
                customized["priority"] = "high"
            
            customized_suggestions.append(customized)
        
        return customized_suggestions

    def get_related_documentation(self, error_type: str) -> List[str]:
        """获取相关文档链接"""
        docs = {
            "type_mismatch": [
                "Cairo 类型系统文档",
                "felt252 类型使用指南",
                "类型转换最佳实践"
            ],
            "ownership_error": [
                "Cairo 所有权系统",
                "引用和借用规则",
                "内存安全编程"
            ],
            "undefined_variable": [
                "变量作用域规则",
                "模块导入系统",
                "命名空间管理"
            ],
            "syntax_error": [
                "Cairo 语法参考",
                "代码格式规范",
                "常见语法错误"
            ],
            "contract_error": [
                "Starknet 合约开发",
                "合约调用机制",
                "合约部署指南"
            ]
        }
        
        return docs.get(error_type, ["Cairo 官方文档"])

    def calculate_confidence(self, error_type: str, pattern_score: float, 
                           context_score: float) -> float:
        """计算诊断置信度"""
        # 基础置信度来自模式匹配
        confidence = pattern_score * 0.6
        
        # 上下文信息增强置信度
        confidence += context_score * 0.3
        
        # 已知错误类型增强置信度
        if error_type != "unknown":
            confidence += 0.1
        
        return min(confidence, 1.0)


# 全局错误分析器实例
error_analyzer = CairoErrorAnalyzer()


def analyze_error(state: ChatState) -> ChatState:
    """错误分析节点"""
    user_text = state["messages"][-1]["content"] if state["messages"] else ""
    cairo_context = state.get("cairo_context", {})
    
    # 提取错误信息
    error_info = error_analyzer.extract_error_info(user_text)
    
    if not error_info["has_error"]:
        # 没有检测到错误，设置默认值
        state["error_diagnosis"] = None
        state["next_action"] = "knowledge_retrieval"
        return state
    
    # 分类错误类型
    error_type, pattern_score = error_analyzer.classify_error_type(user_text)
    
    # 分析根本原因
    root_cause = error_analyzer.analyze_root_cause(error_type, user_text, cairo_context)
    
    # 生成修复建议
    fix_suggestions = error_analyzer.generate_fix_suggestions(error_type, user_text, cairo_context)
    
    # 获取相关文档
    related_docs = error_analyzer.get_related_documentation(error_type)
    
    # 计算置信度
    context_score = 0.5 if cairo_context.get("has_code") else 0.2
    confidence = error_analyzer.calculate_confidence(error_type, pattern_score, context_score)
    
    # 设置错误诊断结果
    state["error_diagnosis"] = ErrorDiagnosisResult(
        error_type=error_type,
        error_patterns=[error_type],
        root_cause=root_cause,
        fix_suggestions=fix_suggestions,
        related_docs=related_docs,
        confidence_score=confidence
    )
    
    # 设置下一步动作
    state["next_action"] = "answer_generation"
    
    return state